package cn.tqfeiyang.smartadmin.commons.toolbox;

import cn.hutool.extra.spring.SpringUtil;
import cn.tqfeiyang.smartadmin.commons.application.SmartAdminConfig;
import cn.tqfeiyang.smartadmin.commons.exception.BusinessException;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

/**
 * EasyExcel工具类
 *
 * @author tqfeiyang
 * @since 2024/9/7 11:17
 */
public class ExcelUtils {

    private ExcelUtils() {}

    public static void exportExcel(List<?> list, Class<?> pojoClass, String title) {
        exportExcel(list, pojoClass, title, ServletUtils.getResponse(), title + ".xlsx");
    }

    public static void exportExcel(List<?> list, Class<?> pojoClass, String title, HttpServletResponse response, String fileName) {
        try {
            response.setCharacterEncoding("utf-8");
            response.setHeader(HttpHeaders.CONTENT_TYPE, MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM) + ";charset=utf-8");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"));
            response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
            EasyExcel.write(response.getOutputStream(), pojoClass)
                    .inMemory(true)
                    .sheet(title)
                    .registerWriteHandler(new CustomWaterMarkHandler(createWatermark()))
                    .doWrite(list);
        } catch (IOException e) {
            throw new BusinessException("导出excel错误: " + e.getMessage());
        }
    }

    private static Watermark createWatermark() {
        SmartAdminConfig config = SpringUtil.getBean(SmartAdminConfig.class);
        if (StringUtils.isNotBlank(config.getWatermarkText())) {
            return new Watermark(config.getWatermarkText());
        } else {
            return null;
        }
    }

    public static void importExcel(MultipartFile file, Class<?> pojoClass, ReadListener<?> listener) {
        try {
            EasyExcel.read(file.getInputStream(), pojoClass, listener)
                    .sheet()
                    .doRead();
        } catch (IOException e) {
            throw new BusinessException("导入excel错误: " + e.getMessage());
        }
    }




//    public static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
//        try {
//            response.setCharacterEncoding("UTF-8");
//            response.setHeader("content-Type", "application/vnd.ms-excel");
//            response.setHeader("Content-Disposition",
//                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//            workbook.write(response.getOutputStream());
//        } catch (IOException e) {
//            throw new RuntimeException(e.getMessage());
//        }
//    }
//
//    public static void exportExcel(HttpServletResponse response, List<?> list, Class<?> pojoClass, String title) {
//        // 使用EasyPoi时，如果传入的是不可修改List就会报错，所以这里需要做一个转换
//        ArrayList dataSet = new ArrayList(list);
//        ExportParams exportParams = new ExportParams(title, title, ExcelType.XSSF);
//        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, dataSet);
//        if (workbook != null) {
//            downLoadExcelX(title + ".xlsx", response, workbook);
//        }
//    }
//
//    public static void exportExcelX(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName, HttpServletResponse response){
//        defaultExportX(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF));
//    }
//
//    private static void defaultExportX(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) {
//        // 使用EasyPoi时，如果传入的是不可修改List就会报错，所以这里需要做一个转换
//        ArrayList dataSet = new ArrayList(list);
//        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, dataSet);
//        if (workbook != null) {
//            downLoadExcelX(fileName, response, workbook);
//        }
//    }
//
//    private static void downLoadExcelX(String fileName, HttpServletResponse response, Workbook workbook) {
//        try {
//            response.setCharacterEncoding("UTF-8");
//            response.setHeader("content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//            response.setHeader("Content-Disposition",
//                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//            workbook.write(response.getOutputStream());
//        } catch (IOException e) {
//            throw new RuntimeException(e.getMessage());
//        }
//    }
//
//    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName,boolean isCreateHeader, HttpServletResponse response){
//        ExportParams exportParams = new ExportParams(title, sheetName);
//        exportParams.setCreateHeadRows(isCreateHeader);
//        defaultExport(list, pojoClass, fileName, response, exportParams);
//
//    }
//
//    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response){
//        defaultExport(list, fileName, response);
//    }
//
//    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
//        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
//        if (workbook != null) {
//            downLoadExcel(fileName, response, workbook);
//        }
//    }
//
//    public static <T> List<T> importExcel(String filePath,Integer titleRows,Integer headerRows, Class<T> pojoClass){
//        if (StringUtils.isBlank(filePath)){
//            return null;
//        }
//        ImportParams params = new ImportParams();
//        params.setTitleRows(titleRows);
//        params.setHeadRows(headerRows);
//        List<T> list = null;
//        try {
//            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
//        }catch (NoSuchElementException e){
//            throw new RuntimeException("模板不能为空");
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new RuntimeException(e.getMessage());
//        }
//        return list;
//    }
//    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass){
//        if (file == null){
//            return null;
//        }
//        ImportParams params = new ImportParams();
//        params.setTitleRows(titleRows);
//        params.setHeadRows(headerRows);
//        List<T> list = null;
//        try {
//            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
//        }catch (NoSuchElementException e){
//            throw new RuntimeException("excel文件不能为空");
//        } catch (Exception e) {
//            throw new RuntimeException(e.getMessage());
//        }
//        return list;
//    }




    @Slf4j
    private static class CustomWaterMarkHandler implements SheetWriteHandler {

        private final Watermark watermark;

        public CustomWaterMarkHandler(Watermark watermark) {
            this.watermark = watermark;
        }

        @Override
        public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
            if (watermark == null) {
                return;
            }

            BufferedImage bufferedImage = createWatermarkImage();
            XSSFWorkbook workbook = (XSSFWorkbook) writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook();
            try {
                // 添加水印的具体操作
                addWatermarkToSheet(workbook, bufferedImage);
            } catch (Exception e) {
                log.error("添加水印出错:", e);
            }

        }

        /**
         * 创建水印图片
         *
         * @return
         */
        private BufferedImage createWatermarkImage() {
            // 获取水印相关参数
            Font font = watermark.getFont();
            int width = watermark.getWidth();
            int height = watermark.getHeight();
            Color color = watermark.getColor();
            String text = watermark.getContent();

            // 创建带有透明背景的 BufferedImage
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = image.createGraphics();

            // 设置画笔字体、平滑、颜色
            g.setFont(font);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(color);

            // 计算水印位置和角度
            int y = watermark.getYAxis();
            int x = watermark.getXAxis();
            AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(-watermark.getAngle()), 0, y);
            g.setTransform(transform);
            // 绘制水印文字
            g.drawString(text, x, y);

            // 释放资源
            g.dispose();

            return image;
        }

        private void addWatermarkToSheet(XSSFWorkbook workbook, BufferedImage watermarkImage) {
            try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                ImageIO.write(watermarkImage, "png", os);
                int pictureIdx = workbook.addPicture(os.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
                XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx);
                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                    // 获取每个Sheet表
                    XSSFSheet sheet = workbook.getSheetAt(i);
                    PackagePartName ppn = pictureData.getPackagePart().getPartName();
                    String relType = XSSFRelation.IMAGES.getRelation();
                    PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
                    sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
                }
            } catch (Exception e) {
                // 处理ImageIO.write可能抛出的异常
                log.error("添加水印图片时发生错误", e);
            }
        }
    }

    @Data
    private static class Watermark {

        public Watermark(String content) {
            this.content = content;
            init();
        }

        public Watermark(String content, Color color, Font font, double angle) {
            this.content = content;
            this.color = color;
            this.font = font;
            this.angle = angle;
            init();
        }

        /**
         * 根据水印内容长度自适应水印图片大小，简单的三角函数
         */
        private void init() {
            FontMetrics fontMetrics = new JLabel().getFontMetrics(this.font);
            int stringWidth = fontMetrics.stringWidth(this.content);
            int charWidth = fontMetrics.charWidth('A');
            this.width = (int) Math.abs(stringWidth * Math.cos(Math.toRadians(this.angle))) + 5 * charWidth;
            this.height = (int) Math.abs(stringWidth * Math.sin(Math.toRadians(this.angle))) + 5 * charWidth;
            this.yAxis = this.height;
            this.xAxis = charWidth;
        }

        /**
         * 水印内容
         */
        private String content;

        /**
         * 画笔颜色
         */
        private Color color = new Color(239,239,239);

        /**
         * 字体样式
         */
        private Font font = new Font("Microsoft YaHei", Font.BOLD, 26);

        /**
         * 水印宽度
         */
        private int width;

        /**
         * 水印高度
         */
        private int height;

        /**
         * 倾斜角度，非弧度制
         */
        private double angle = 25;

        /**
         * 字体的y轴位置
         */
        private int yAxis = 50;

        /**
         * 字体的X轴位置
         */
        private int xAxis;

        /**
         * 水平倾斜度
         */
        private double shearX = 0.1;

        /**
         * 垂直倾斜度
         */
        private double shearY = -0.26;
    }
}
